#pragma once

#include "DynamicRHI.h"

namespace RenderSystem
{
	/**
	* A rendering resource which is owned by the rendering thread.
	*/
	typedef std::list<FRenderResource*> ResourceList;
	typedef ResourceList::iterator		ResourceListIterator;
	typedef ResourceList::const_iterator ResourceListConstIterator;


	class FRenderResource
	{
	public:
		/**
		* @return The global initialized resource list.
		*/
		static ResourceList*& GetResourceList();

		/**
		* Minimal initialization constructor.
		*/
		FRenderResource():
		m_bInitialized(false)
		{}

		/**
		* Destructor used to catch unreleased resources.
		*/
		virtual ~FRenderResource();

		/**
		* Initializes the dynamic RHI resource and/or RHI render target used by this resource.
		* Called when the resource is initialized, or when reseting all RHI resources.
		* This is only called by the rendering thread.
		*/
		virtual void InitDynamicRHI() {}

		/**
		* Releases the dynamic RHI resource and/or RHI render target resources used by this resource.
		* Called when the resource is released, or when reseting all RHI resources.
		* This is only called by the rendering thread.
		*/
		virtual void ReleaseDynamicRHI() {}

		/**
		* Initializes the RHI resources used by this resource.
		* Called when the resource is initialized, or when reseting all RHI resources.
		* This is only called by the rendering thread.
		*/
		virtual void InitRHI() {}

		/**
		* Releases the RHI resources used by this resource.
		* Called when the resource is released, or when reseting all RHI resources.
		* This is only called by the rendering thread.
		*/
		virtual void ReleaseRHI() {}

		/**
		* Initializes the resource.
		* This is only called by the rendering thread.
		*/
		virtual void InitResource();

		/**
		* Prepares the resource for deletion.
		* This is only called by the rendering thread.
		*/
		virtual void ReleaseResource();

		/**
		* If the resource's RHI has been initialized, then release and reinitialize it.  Otherwise, do nothing.
		* This is only called by the rendering thread.
		*/
		void UpdateRHI();

		/**
		* @return The resource's friendly name.  Typically a UObject name.
		*/
		virtual String GetFriendlyName() const { return TEXT("undefined"); }

		// Assignment operator.
		void operator=(const FRenderResource& OtherResource) {}

		// Accessors.
		bool IsInitialized() const { return m_bInitialized; }

	protected:

		/** This resource's link in the global resource list. */
		ResourceList m_ResourceLink;

		/** True if the resource has been initialized. */
		bool m_bInitialized;
	};

	/**
	* Sends a message to the rendering thread to initialize a resource.
	* This is called in the game thread.
	*/
	extern void BeginInitResource(FRenderResource* Resource);

	/**
	* Sends a message to the rendering thread to update a resource.
	* This is called in the game thread.
	*/
	extern void BeginUpdateResourceRHI(FRenderResource* Resource);

	/**
	* Sends a message to the rendering thread to release a resource.
	* This is called in the game thread.
	*/
	extern void BeginReleaseResource(FRenderResource* Resource);

	/**
	* Sends a message to the rendering thread to release a resource, and spins until the rendering thread has processed the message.
	* This is called in the game thread.
	*/
	extern void ReleaseResourceAndFlush(FRenderResource* Resource);

	/**
	* A texture.
	*/
	class FTexture : public FRenderResource
	{
	public:
		/** The texture's RHI resource. */
		FTextureRHIRef		TextureRHI;

		/** The sampler state to use for the texture. */
		FSamplerStateRHIRef SamplerStateRHI;

		/** The last time the texture has been bound */
		mutable DOUBLE		LastRenderTime;

		/** TRUE if the texture is in a greyscale texture format. */
		bool				bGreyScaleFormat;

		/**
		* TRUE if the texture is in the same gamma space as the intended rendertarget (e.g. screenshots).
		* The texture will have sRGB==FALSE and bIgnoreGammaConversions==TRUE, causing a non-sRGB texture lookup
		* and no gamma-correction in the shader.
		*/
		bool				bIgnoreGammaConversions;

		/**
		* Default constructor, initializing last render time to 0.
		*/
		FTexture()
			: LastRenderTime(0.0)
			, bGreyScaleFormat(FALSE)
			, bIgnoreGammaConversions(FALSE)
		{}

		// Destructor
		virtual ~FTexture() {}

		// FRenderResource interface.
		virtual void ReleaseRHI()
		{
			TextureRHI.SafeRelease();
			SamplerStateRHI.SafeRelease();
		}
		/** Returns the width of the texture in pixels. */
		virtual UINT GetSizeX() const
		{
			return 0;
		}
		/** Returns the height of the texture in pixels. */
		virtual UINT GetSizeY() const
		{
			return 0;
		}

		/**
		* @return The resource's friendly name.
		*/
		virtual String GetFriendlyName() const { return TEXT("FTexture"); }
	};

	/**
	* A vertex buffer.
	*/
	class FVertexBuffer : public FRenderResource
	{
	public:
		FVertexBufferRHIRef VertexBufferRHI;

		/** Destructor. */
		virtual ~FVertexBuffer() {}

		// FRenderResource interface.
		virtual void ReleaseRHI()
		{
			VertexBufferRHI.SafeRelease();
		}

		/**
		* @return The resource's friendly name.
		*/
		virtual String GetFriendlyName() const { return TEXT("FVertexBuffer"); }
	};

	/**
	* A vertex buffer with a single color component.  This is used on meshes that don't have a color component
	* to keep from needing a separate vertex factory to handle this case.
	*/
	class FNullColorVertexBuffer : public FVertexBuffer
	{
	public:
		/** 
		* Initialize the RHI for this rendering resource 
		*/
		virtual void InitRHI()
		{
			// create a static vertex buffer
			VertexBufferRHI = RHICreateVertexBuffer(sizeof(DWORD), NULL, RUF_Static);
			DWORD* Vertices = (DWORD*)RHILockVertexBuffer(VertexBufferRHI, 0, sizeof(DWORD),FALSE);
			Vertices[0] = Common::FColor(255, 255, 255, 255).DWColor();
			RHIUnlockVertexBuffer(VertexBufferRHI);
		}
	};

	/** The global null color vertex buffer, which is set with a stride of 0 on meshes without a color component. */
	//extern TGlobalResource<FNullColorVertexBuffer> GNullColorVertexBuffer;

	/**
	* An index buffer.
	*/
	class FIndexBuffer : public FRenderResource
	{
	public:
		FIndexBufferRHIRef IndexBufferRHI;

		/** Destructor. */
		virtual ~FIndexBuffer() {}

		// FRenderResource interface.
		virtual void ReleaseRHI()
		{
			IndexBufferRHI.SafeRelease();
		}

		/**
		* @return The resource's friendly name.
		*/
		virtual String GetFriendlyName() const { return TEXT("FIndexBuffer"); }
	};
}